package cn.kt.test;

import cn.kt.domin.Person;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * Created by tao.
 * Date: 2021/9/3 16:02
 * 描述:  Java 8 Stream
 * Stream流属于管道流,只能被消费(使用)一次
 * 第一个Stream流调用完毕方法,数据就会流转到下一个Stream上
 * 而这时第一个Stream流已经使用完毕,就会关闭了
 * 所以第一个Stream流就不能再调用方法了
 */


public class Demo7 {
    public static void main(String args[]) {
        // 计算空字符串
        List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd", "", "jkl");
        List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
        List<Integer> integers = Arrays.asList(1, 2, 13, 4, 15, 6, 17, 8, 19);
        // 输出10个随机数
        Random random = new Random();
        System.out.println("使用 Java 8: ");
        System.out.println("列表: " + strings);

        // 1. 顺序流处理
        long count = strings.stream().filter(String::isEmpty).count();
        System.out.println("空字符串的数量为（顺序流）: " + count);

        // 2. 并行处理
        count = strings.parallelStream().filter(String::isEmpty).count();
        System.out.println("空字符串的数量为（并行处理）: " + count);

        // 3. filter 方法用于通过设置的条件过滤出元素。
        count = strings.stream().filter(string -> string.length() == 3).count();
        System.out.println("字符串长度为 3 的数量为: " + count);

        // 4. Collectors 类实现了很多归约操作，例如将流转换成集合和聚合元素。Collectors 可用于返回列表或字符串
        List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
        System.out.println("筛选后的列表: " + filtered);

        String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", "));
        System.out.println("合并字符串: " + mergedString);

        // 5. map 方法用于映射每个元素到对应的结果
        List<Integer> squaresList = numbers.stream().map(i -> i * i).distinct().collect(Collectors.toList());
        System.out.println("Squares List: " + squaresList);
        System.out.println("列表: " + integers);

        // 6. 统计：主要用于int、double、long等基本类型上
        IntSummaryStatistics stats = integers.stream().mapToInt((x) -> x).summaryStatistics();
        System.out.println("列表中最大的数 : " + stats.getMax());
        System.out.println("列表中最小的数 : " + stats.getMin());
        System.out.println("所有数之和 : " + stats.getSum());
        System.out.println("平均数 : " + stats.getAverage());
        System.out.println("随机数: ");

        // 7. limit 方法用于获取指定数量的流
        System.out.print("limit 获取前 x 个指定数量的流：");
        integers.stream().limit(5).sorted().forEach(System.out::println);
        System.out.print("skip 获取指定数量的流：");
        integers.stream().skip(2).forEach(System.out::println);

        // 8. reduce 归约：也称缩减，顾名思义，是把一个流缩减成一个值，能实现对集合求和、求乘积和求最值操作。
        List<Integer> list = Arrays.asList(1, 3, 2, 8, 11, 4);
        // 求和方式1
        Optional<Integer> sum = list.stream().reduce((x, y) -> x + y);
        // 求和方式2
        Optional<Integer> sum2 = list.stream().reduce(Integer::sum);
        // 求和方式3
        Integer sum3 = list.stream().reduce(0, Integer::sum);
        // 求乘积
        Optional<Integer> product = list.stream().reduce((x, y) -> x * y);
        // 求最大值方式1
        Optional<Integer> max = list.stream().reduce((x, y) -> x > y ? x : y);
        // 求最大值写法2
        Integer max2 = list.stream().reduce(1, Integer::max);
        System.out.println("list求和：" + sum.get() + "," + sum2.get() + "," + sum3);
        System.out.println("list求积：" + product.get());
        System.out.println("list求和：" + max.get() + "," + max2);

        //9. 归集(toList/toSet/toMap) 因为流不存储数据，那么在流中的数据完成处理后，需要将流中的数据重新归集到新的集合里。toList、toSet和toMap比较常用，另外还有toCollection、toConcurrentMap等复杂一些的用法。
        List<Integer> arrList = Arrays.asList(1, 6, 3, 4, 6, 7, 9, 6, 20);
        List<Integer> listNew = arrList.stream().filter(x -> x % 2 == 0).collect(Collectors.toList());
        Set<Integer> set = arrList.stream().filter(x -> x % 2 == 0).collect(Collectors.toSet());

        List<Person> personList = new ArrayList<Person>();
        personList.add(new Person("Tom", 8900, 23, "male", "New York"));
        personList.add(new Person("Jack", 7000, 25, "male", "Washington"));
        personList.add(new Person("Lily", 7800, 21, "female", "Washington"));
        personList.add(new Person("Anni", 8200, 24, "female", "New York"));

        Map<?, Person> map = personList.stream().filter(p -> p.getSalary() > 8000)
                .collect(Collectors.toMap(Person::getName, p -> p));
        System.out.println("toList:" + listNew);
        System.out.println("toSet:" + set);
        System.out.println("toMap:" + map);

        //10. 接合(joining) joining可以将stream中的元素用特定的连接符（没有的话，则直接连接）连接成一个字符串。
        List<String> slist = Arrays.asList("A", "B", "C");
        String string = slist.stream().collect(Collectors.joining("-"));
        System.out.println("拼接后的字符串：" + string);
    }
}